package com.leetcode.array;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 *打乱数组
 * 给你一个整数数组 nums ，设计算法来打乱一个没有重复元素的数组。
 * 实现 Solution class:
 * Solution(int[] nums) 使用整数数组 nums 初始化对象
 * int[] reset() 重设数组到它的初始状态并返回
 * int[] shuffle() 返回数组随机打乱后的结果
 * 示例：
 *
 * 输入
 * ["Solution", "shuffle", "reset", "shuffle"]
 * [[[1, 2, 3]], [], [], []]
 * 输出
 * [null, [3, 1, 2], [1, 2, 3], [1, 3, 2]]
 *
 * 解释
 * Solution solution = new Solution([1, 2, 3]);
 * solution.shuffle();    // 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。例如，返回 [3, 1, 2]
 * solution.reset();      // 重设数组到它的初始状态 [1, 2, 3] 。返回 [1, 2, 3]
 * solution.shuffle();    // 随机返回数组 [1, 2, 3] 打乱后的结果。例如，返回 [1, 3, 2]
 *
 * 提示：
 *
 * 1 <= nums.length <= 200
 * -106 <= nums[i] <= 106
 * nums 中的所有元素都是 唯一的
 * 最多可以调用 5 * 104 次 reset 和 shuffle
 *
 * 作者：力扣 (LeetCode)
 * 链接：https://leetcode-cn.com/leetbook/read/top-interview-questions/xmchc3/
 * 来源：力扣（LeetCode）
 * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
 *
 */
class Code384 {
    int[] tarArr = null;
    int[] tempArr = null;
    Random random = new Random();
    public static void main(String[] args) {
        int[] numarr = new int[]{0,1,2,3,4,5};
        Code384 solution = new Code384(numarr);
        int[] shuffle = solution.shuffle();
        for(int k : shuffle){
            System.out.println(k);
        }
        System.out.println("***********");
        int[] reset = solution.reset();
        for(int k : reset){
            System.out.println(k);
        }

    }

    /**
     * 暴力算法简单的来说就是把每个数放在一个 ”帽子“ 里面，每次从 ”帽子“ 里面随机摸一个数出来，直到 “帽子” 为空。下
     * 面是具体操作，首先我们把数组 array 复制一份给数组 aux，之后每次随机从 aux 中取一个数，为了防止数被重复取出，
     * 每次取完就把这个数从 aux 中移除。重置 的实现方式很简单，只需把 array 恢复称最开始的状态就可以了。
     *
     * 作者：LeetCode
     * 链接：https://leetcode-cn.com/problems/shuffle-an-array/solution/da-luan-shu-zu-by-leetcode/
     * 来源：力扣（LeetCode）
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     * @author ymy
     * @date 2021/11/11 9:31
     * @return java.util.List<java.lang.Integer>
     */
    public List<Integer> copy(){
        List<Integer> list = new ArrayList<>(tarArr.length);
        for(int i = 0;i<tarArr.length;i++){
            list.add(tarArr[i]);
        }
        return list;
    }
    public Code384(int[] nums) {
        tarArr = nums;
        tempArr = tarArr.clone();
    }

    /** Resets the array to its original configuration and return it. */
    public int[] reset1() {
        tarArr = tempArr.clone();
        return tarArr;
    }

    /** Returns a random shuffling of the array. */
    public int[] shuffle1() {
        List<Integer> copy = copy();
        for(int i = 0;i<tarArr.length-1;i++){
            Integer integer = copy.get(random.nextInt(copy.size()));
            tarArr[i] = integer;
            copy.remove(integer);
        }
        return tarArr;
    }

    /**
     * Fisher-Yates 洗牌算法
     *
     * @author ymy
     * @date 2021/11/11 9:34
     * @param null
     * @return null
     */
    /** Resets the array to its original configuration and return it. */
    public int[] reset() {
        tarArr = tempArr.clone();
        return tarArr;
    }

    /** Returns a random shuffling of the array. */
    public int[] shuffle() {
        for(int i = 0;i<tarArr.length;i++){
            int random = getRandom(i);
            swap(i,random);
        }
        return tarArr;
    }

    public void swap(int m,int n){
        int temp = tarArr[m];
        tarArr[m] = tarArr[n];
        tarArr[n] = temp;
    }
    public int getRandom(int index){
        int s = random.nextInt(tarArr.length-index);
        return index+s;
    }
}
